![Global Acceleratorで作成されるセキュリティグループをALBのセキュリティグループで許可するカスタムリソース作ってみた](https://devio2023-media.developers.io/wp-content/uploads/2022/08/aws-global-accelerator.png)
Global Acceleratorで作成されるセキュリティグループをALBのセキュリティグループで許可するカスタムリソース作ってみた
こんにちは!AWS事業本部コンサルティング部のたかくに(@takakuni_)です。
今回は、Global Acceleratorエンドポイント作成時にAWS側で作成されるGlobal Accelerator用のセキュリティグループをALBのセキュリティグループに紐づけるカスタムリソースを作ってみました。
なぜそんなことをしているのか
Global Acceleratorエンドポイントグループ作成時、Global Acceleratorはエンドポイントが存在するVPCごとに1つずつセキュリティグループを作成します。
つまり、セキュリティグループを作成するのはCloudFormationではなく、Global Accelerator側となります。
そのため、Global AcceleratorエンドポイントとALBを同時に作成するテンプレートの場合、CloudFormation側でGlobal Acceleratorのセキュリティグループを定義していないので、ALBのセキュリティグループでGlobal Acceleratorのセキュリティグループを許可するルールが作成できない事象が発生します。
もちろんですが、Global Acceleratorエンドポイントグループを見ても、返り値としてセキュリティグループを取得することができませんでした。
AWS::GlobalAccelerator::EndpointGroup
今回は、CloudFormationテンプレートを利用して1発で設定する方法が2つあったのでご紹介します。
方法1(非推奨)
方法1は、Global Acceleratorエンドポイントグループ作成前に、セキュリティグループを作ってしまう方法です。
Global Acceleratorで作成されるセキュリティグループの名前は、私が検証した限り「GlobalAccelerator」と名前がついたセキュリティグループが対象VPCに作成されていました。
そのため、次のようにGlobal Acceleratorエンドポイントグループ作成前にセキュリティグループを作成します。
Resources: AlbSg: Type: AWS::EC2::SecurityGroup Properties: VpcId: !Ref VpcId GroupName: !Sub "${PrjPrefix}-alb-sg" GroupDescription: !Sub "${PrjPrefix}-alb-sg" Tags: - Key: Name Value: !Sub "${PrjPrefix}-alb-sg" Alb: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub "${PrjPrefix}-alb" Type: application IpAddressType: ipv4 Scheme: internet-facing SecurityGroups: - !GetAtt AlbSg.GroupId Subnets: !Ref SubnetIds Tags: - Key: Name Value: !Sub "${PrjPrefix}-alb" # Global Accelerator用のSGを先に作る GlobalAcceleratorSg: Type: AWS::EC2::SecurityGroup Properties: VpcId: !Ref VpcId GroupName: "GlobalAccelerator" # 名前は固定 GroupDescription: !Sub "${PrjPrefix}-ga-sg" Tags: - Key: Name Value: !Sub "${PrjPrefix}-ga-sg" AlbFromGaIngress: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: !GetAtt AlbSg.GroupId Description: GlobalAccelerator Communication FromPort: 80 ToPort: 80 IpProtocol: tcp SourceSecurityGroupId: !GetAtt GlobalAcceleratorSg.GroupId AcceleratorListeneralb: Type: AWS::GlobalAccelerator::EndpointGroup Properties: EndpointGroupRegion: Ref: AWS::Region ListenerArn: Fn::GetAtt: - AcceleratorListener - ListenerArn EndpointConfigurations: - EndpointId: Ref: Alb DependsOn: - GlobalAcceleratorSg # 明示的に依存関係を持たせる
ただし、以下のドキュメントにある通り、Global Acceleratorが作成するセキュリティグループを操作するのは非推奨とされています。
グローバルアクセラレータによって作成されたセキュリティグループ
グローバルアクセラレータとセキュリティグループを使用する場合は、次の情報とベストプラクティスを確認してください。
Global Accelerator は、Elastic Network インターフェイスに関連付けられているセキュリティグループを作成します。システムによって禁止されるわけではありませんが、これらのグループのセキュリティグループ設定を編集しないでください。 グローバルアクセラレータは、作成したセキュリティグループを削除しません。ただし、Global Accelerator では、アカウントのアクセラレータのエンドポイントでelastic network interface が使用されていない場合、エラスティックネットワークインターフェイスは削除されます。 Global Accelerator によって作成されたセキュリティグループは、保守する他のセキュリティグループのソースグループとして使用できますが、Global Accelerator は VPC で指定したターゲットにのみトラフィックを転送します。 Global Accelerator で作成されたセキュリティグループのルールを変更すると、エンドポイントが異常になることがあります。その場合は、AWS サポート詳細については、 グローバルアクセラレータは、VPC ごとに特定のセキュリティグループを作成します。特定の VPC 内のエンドポイント用に作成された Elastic ネットワークインターフェイスは、elastic network interface が関連付けられているサブネットに関係なく、すべて同じセキュリティグループを使用します。
クライアント IP アドレスの保存に関するベストプラクティス
方法2(おすすめ)
というわけで、Global Acceleratorが作成するセキュリティグループを操作せずに設定する方法が方法2になります。
具体的には、Global Acceleratorが作成したセキュリティグループIDを取得してALBに許可するカスタムリソースになります。
以下のようにカスタムリソースとして設定することで、Global Acceleratorの非推奨項目を回避しつつALBに設定ができました。
AWSTemplateFormatVersion: "2010-09-09" Description: Terraform pipeline template. Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: "Project Name Prefix" Parameters: - PrjPrefix - Label: default: "Network Configration" Parameters: - VpcId - SubnetIds Parameters: PrjPrefix: Type: String VpcId: Type: AWS::EC2::VPC::Id SubnetIds: Type: List<AWS::EC2::Subnet::Id> Resources: # ALB AlbSg: Type: AWS::EC2::SecurityGroup Properties: VpcId: !Ref VpcId GroupName: !Sub "${PrjPrefix}-alb-sg" GroupDescription: !Sub "${PrjPrefix}-alb-sg" Tags: - Key: Name Value: !Sub "${PrjPrefix}-alb-sg" Alb: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub "${PrjPrefix}-alb" Type: application IpAddressType: ipv4 Scheme: internet-facing SecurityGroups: - !GetAtt AlbSg.GroupId Subnets: !Ref SubnetIds Tags: - Key: Name Value: !Sub "${PrjPrefix}-alb" AlbTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 30 HealthCheckPath: /healthcheck HealthCheckPort: 80 HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 6 HealthyThresholdCount: 3 Name: !Sub "${PrjPrefix}-alb" Port: 80 Protocol: HTTP UnhealthyThresholdCount: 3 TargetType: ip VpcId: !Ref VpcId AlbListerner: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref AlbTargetGroup LoadBalancerArn: !Ref Alb Port: 80 Protocol: HTTP # GlobalAccelerator Accelerator: Type: AWS::GlobalAccelerator::Accelerator Properties: Name: !Sub "${PrjPrefix}-ga" Enabled: true AcceleratorListener: Type: AWS::GlobalAccelerator::Listener Properties: AcceleratorArn: Fn::GetAtt: - Accelerator - AcceleratorArn PortRanges: - FromPort: 80 ToPort: 80 Protocol: TCP ClientAffinity: NONE AcceleratorListenerAlb: Type: AWS::GlobalAccelerator::EndpointGroup Properties: EndpointGroupRegion: Ref: AWS::Region ListenerArn: Fn::GetAtt: - AcceleratorListener - ListenerArn EndpointConfigurations: - EndpointId: Ref: Alb # Security Group ModifySecrityGroupRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole Path: / ManagedPolicyArns: - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - "arn:aws:iam::aws:policy/job-function/NetworkAdministrator" RoleName: !Sub "${PrjPrefix}-modify-security-group" ModifySecrityGroupLog: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/aws/lambda/${PrjPrefix}-modify-security-group" ModifySecrityGroupFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${PrjPrefix}-modify-security-group" Code: ZipFile: | import json import boto3 import cfnresponse def handler(event, context): vpc_id = event['ResourceProperties']['VpcId'] alb_sg_id = event['ResourceProperties']['AlbSgId'] alb_lintener_port = int(event['ResourceProperties']['AlbListernerPort']) try: if event['RequestType'] == 'Create': ec2 = boto3.client('ec2') globalaccelerator_sg_id = ec2.describe_security_groups( Filters=[ { 'Name': 'vpc-id', 'Values': [ vpc_id ] }, { 'Name': 'group-name', 'Values': [ 'GlobalAccelerator' ] } ] )['SecurityGroups'][0]['GroupId'] response = ec2.authorize_security_group_ingress( GroupId = alb_sg_id, IpPermissions = [ { 'FromPort': alb_lintener_port, 'ToPort': alb_lintener_port, 'IpProtocol': 'tcp', 'UserIdGroupPairs': [ { 'GroupId': globalaccelerator_sg_id, 'Description': 'GlobalAccelerator Communication' } ] } ] ) cfnresponse.send(event, context, cfnresponse.SUCCESS, response) if event['RequestType'] == 'Delete': ec2 = boto3.client('ec2') globalaccelerator_sg_id = ec2.describe_security_groups( Filters=[ { 'Name': 'vpc-id', 'Values': [ vpc_id ] }, { 'Name': 'group-name', 'Values': [ 'GlobalAccelerator' ] } ] )['SecurityGroups'][0]['GroupId'] response = ec2.revoke_security_group_ingress( GroupId = alb_sg_id, IpPermissions = [ { 'FromPort': alb_lintener_port, 'ToPort': alb_lintener_port, 'IpProtocol': 'tcp', 'UserIdGroupPairs': [ { 'GroupId': globalaccelerator_sg_id, 'Description': 'GlobalAccelerator Communication' } ] } ] ) cfnresponse.send(event, context, cfnresponse.SUCCESS, {'Response': 'Success'}) if event['RequestType'] == 'Update': cfnresponse.send(event, context, cfnresponse.SUCCESS, {'Response': 'Success'}) except Exception as e: print(e) cfnresponse.send(event, context, cfnresponse.FAILED, {}) Handler: index.handler MemorySize: 128 Role: !GetAtt ModifySecrityGroupRole.Arn Runtime: "python3.9" Timeout: 60 Tags: - Key: "Name" Value: !Sub "${PrjPrefix}-modify-security-group" DependsOn: ModifySecrityGroupLog ModifySecrityGroup: Type: Custom::ModifySecrityGroup Properties: ServiceToken: !GetAtt ModifySecrityGroupFunction.Arn VpcId: !Ref VpcId AlbSgId: !GetAtt AlbSg.GroupId AlbListernerPort: 80 DependsOn: - AcceleratorListenerAlb
まとめ
以上、「Global AcceleratorのセキュリティグループをALBのセキュリティグループで許可するカスタムリソース作ってみた」でした。
Global Accelerator利用時に参考になるととても嬉しいです。
以上、AWS事業本部コンサルティング部のたかくに(@takakuni_)でした!